// 实现这个项目的构建任务
const { src, dest, parallel, series, watch } = require("gulp")
// series 异步执行， parallel， 同步执行
const browserSync = require("browser-sync")
const bServer = browserSync.create()
// 此插件作用直接将package.json中的插件统一管理，使用插件直接plugin.名称， 
// 如plugin.sass()
const loadPlugins = require("gulp-load-plugins")
const plugin = loadPlugins()

const del = require("del")
// 向模板文件传输的数据
const data = {
  // 只配置发布和临时目录，完整配置请看zce-gulp-demo
  build: {
    dist: "dist",
    temp: "temp"
  },
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}
// 删除指定目录
const clean = () => {
  return del([data.build.dist, data.build.temp])
}
// src 第二个参数
// 编译样式是一个对象，base属性配输出的路径是否保留原有路径，也可以理解为输出路径和源文件一致
// 如原来在src/assets/styles/main.scss  输出路径为/dist/assets/styles/main.css
// dest("temp") 输出到临时文件目录，避免直接输出到dist， 避免编译冲突，导致出错
const styles = () => {
  return src("src/assets/styles/*.scss", { base: "src"})
  // { outputStyle: 'expanded'} 去掉缩进的、扩展css代码
  .pipe(plugin.sass({ outputStyle: 'expanded'}))
  .pipe(dest(data.build.temp))
  .pipe(bServer.reload({ stream: true}))
}
// 编译js脚本文件
const scripts = () => {
  return src("src/assets/scripts/*.js", { base: "src"})
  // 使用babel 转换es语法
  .pipe(plugin.babel({ presets: ['@babel/preset-env'] }))
  .pipe(dest(data.build.temp))
  .pipe(bServer.reload({ stream: true}))
}
// 编译html文件
const pages = () => {
  // 匹配src下面的任意目录的html文件
  return src("src/**/*.html", { base: "src"})
  // 将数据注入swig模板
  .pipe(plugin.swig({ data, defaults: { cache: false} }))
  .pipe(dest(data.build.temp))
  .pipe(bServer.reload({ stream: true}))
}

// 编译图片文件
const images = () => {
  return src("src/assets/images/**", { base: "src"})
  // 压缩图片
  .pipe(plugin.imagemin({
    optimizationLevel: 5, //类型：Number  默认：3  取值范围：0-7（优化等级）
    progressive: true, //类型：Boolean 默认：false 无损压缩jpg图片
    interlaced: true, //类型：Boolean 默认：false 隔行扫描gif进行渲染
    multipass: true, //类型：Boolean 默认：false 多次优化svg直到完全优化
    svgoPlugins: [
      {
        removeViewBox: true //不要移除svg的viewbox属性
      }
    ]
  }))
  .pipe(dest(data.build.dist))
}
// 编译字体
const fonts = () => {
  return src("src/assets/fonts/**", { base: "src"})
  // 普通压缩一下
  .pipe(plugin.imagemin())
  .pipe(dest(data.build.dist))
}

// 编译其他部分文件
const extra = () => {
  return src("public/**", { base: "public"})
  .pipe(dest(data.build.dist))
}

// 开发服务器
const devServer = () => {
  // 可能会因为swig 模板引擎缓存机制导致页面不会变化，
  // 需要额外将swig选项中的cache选项设置为false
  watch("src/assets/styles/**.css", styles)
  watch("src/assets/scripts/**.js", scripts)
  watch("src/*.html", pages)
  // 统一监听行为一致的操作。
  watch([
    "src/assets/images/**",
    "src/assets/fonts/**",
    "public/**",
  ], bServer.reload)

  bServer.init({
    notify: false,
    port: 8080,
    open: true,
    server: {
      baseDir: [data.build.temp, 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 将HTML引用的多个CSS和JS合并起来，减小依赖的文件个数，从而减少浏览器发起的请求次数。
const useref = () => {
  return src(`${data.build.temp}/*.html`, { base: data.build.temp})
  .pipe(plugin.useref({ searchPath: [data.build.temp, '.']}))
  // html => gulp-htmlmin, css => gulp-clean-css, js=> gulp-uglify
  // 判断文件类型 gulp-if 进行压缩
  .pipe(plugin.if(/\.js$/, plugin.uglify()))
  .pipe(plugin.if(/\.css$/, plugin.cleanCss()))
  .pipe(plugin.if(/\.html$/, plugin.htmlmin({ 
    collapseWhitespace: true, // 去除多余的空格
    minifyCSS: true, 
    minifyJS: true,
  })))
  // 输出到真正的目录
  .pipe(dest(data.build.dist))
}

const compile = parallel(styles, scripts, pages)
const build = series(clean, parallel(
  series(compile, useref), 
  images, 
  fonts, 
  extra
))

const serve = series(compile, devServer)

// 获取命令行参数
let options = require("minimist")( process.argv.slice(2) );

// 发布前判断是否指定发布目录并替换
const deployOper = (done) => {
  if(options.production) {
    if (options.dist) data.build.dist = options.dist
    if (options.temp) data.build.temp = options.temp
  }
  done()
}

const deploy = series(deployOper, build, () => {
  console.log("After publishing, delete the temporary directory")
  return del(data.build.temp)
})
// 检查代码, 这里做一个简单校验，更多规则遵循eslint 规范
const lint = () => {
  return src('src/**/*.js', {base: "src"})
  .pipe(plugin.eslint({
    'rules':{
      'quotes': [1, 'single'],
      'semi': [1, 'always']
    },
    parserOptions: {
      "ecmaVersion": 6, //指定ECMAScript支持的版本，6为ES6
      "sourceType": "module", //指定来源的类型，有两种”script”或”module”
      "ecmaFeatures": {
          "jsx": true//启动JSX
      },
    }
  }))
  .pipe(plugin.eslint.format())
  // Brick on failure to be super strict
  .pipe(plugin.eslint.failOnError())
}

// "clean": "gulp clean",
// "lint": "gulp lint",
// "serve": "gulp serve",
// "build": "gulp build",
// "start": "gulp start",
// "deploy": "gulp deploy --production"

module.exports = {
  clean,
  build,
  serve,
  start: serve,
  deploy,
  lint
}
